﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Love.Awesome.FluxNET
{
    /// <summary>
    /// 平滑函数。
    /// </summary>
    public enum EasingFunctionType
    {
        Quad, Cubic, Quart, Quint, Expo, Sine, Circle, Back, Elastic
    }

    /// <summary>
    /// 缓动方式。
    /// </summary>
    public enum EasingInOutMode
    {
        In, Out, InOut, None
    }

    internal static class EasingFunctionMapper
    {
        private static Dictionary<EasingFunctionType, Func<float, float>> _map;
        static EasingFunctionMapper()
        {
            _map = new Dictionary<EasingFunctionType, Func<float, float>>();

            _map.Add(EasingFunctionType.Quad, (p) => p * p);
            _map.Add(EasingFunctionType.Cubic, p => p * p * p);
            _map.Add(EasingFunctionType.Quart, p => p * p * p * p);
            _map.Add(EasingFunctionType.Quint, p => p * p * p * p * p);
            _map.Add(EasingFunctionType.Expo, p => (float)Math.Pow(2, 10 * (p - 1)));
            _map.Add(EasingFunctionType.Sine, p => (float)(-Math.Cos(p * Math.PI * 0.5)) + 1);
            _map.Add(EasingFunctionType.Circle, p => (float)-(Math.Sqrt(1 - (p * p)) - 1));
            _map.Add(EasingFunctionType.Back, p => p * p * (2.7f * p - 1.7f));
            _map.Add(EasingFunctionType.Elastic, p => (float)(-(Math.Pow(2, (10f * (p - 1f))) * Math.Sin((p - 1.075f) * (Math.PI * 2f) / .3f))));
        }

        public static float CalculateEasingFunction(EasingFunctionType easingFunctionType, EasingInOutMode easingInOutMode, float value)
        {
            if (value < 0) value = 0;
            if (value > 1) value = 1;
            if (!_map.ContainsKey(easingFunctionType)) return 0;
            var handler = _map[easingFunctionType];
            switch (easingInOutMode)
            {
                case EasingInOutMode.In:
                    return handler(value);
                case EasingInOutMode.Out:
                    return 1 - handler(1 - value);
                case EasingInOutMode.InOut:
                    value = value * 2;
                    if(value < 1)
                    {
                        return handler(value)/2;
                    }
                    else
                    {
                        value = 2 - value;
                        return 0.5f * (1 - handler(value)) + 0.5f;
                    }
                default:
                    return handler(value);
            }
        }

    }
}
